#include "config.h"

#include <clx/libECM.h>
#include <clx/ecm_list.h>

static char	*inputfile;

#define ERR(fmt, ...)	ECMERR("ERR: ms2check: " fmt, ## __VA_ARGS__)

typedef struct {
	ecm_uint32	tick_start, tick_end;
	ecm_uint32	rank;
	struct list_head	list;
} session_t;

static LIST_HEAD(sessions);
static ecm_uint32	start, end;
static ecm_uint32	max_rank;

static void
usage(void)
{
	ecm_fprintf(ecm_stderr,
"Usage: ms2check [ <options> ] <log file>\n"
	);
}

static void
parse_args(int argc, char *argv[])
{
	int	c;

	while ((c = ecm_getopt(argc, argv, "h")) != -1) {
		switch(c) {
		case 'h':
			usage();
			ecm_exit(0);
		default:
			usage();
			ecm_exit(1);
		}
	}

	inputfile = ecm_strdup(argv[ecm_optind]);
}

static void
create_session(ecm_uint32 tick_start, ecm_uint32 tick_end, ecm_uint32 rank)
{
	session_t	*session;

	session = ecm_malloc(sizeof(session_t));
	session->tick_start = tick_start;
	session->tick_end = tick_end;
	session->rank = rank;
	list_add_tail(&session->list, &sessions);
}

static void
load_session(void)
{
	FILE	*fp;
	char	buf[4096];

	fp = ecm_fopen(inputfile, "r");
	if (fp == NULL) {
		ERR("%s: cannot open");
		ecm_exit(1);
	}

	while ((ecm_fgets(buf, 4096, fp))) {
		ecm_uint32	tick_start, tick_end;
		ecm_uint32	rank;

		if (*buf == '#')
			continue;
		if (ecm_sscanf(buf, "%*u %*u %*u %u %u-%u", &rank, &tick_start, &tick_end) != 3) {
			ERR("%s: line error", buf);
			continue;
		}
		if (start == 0)
			start = tick_start;
		end = tick_end;
		if (max_rank < rank)
			max_rank = rank;
		create_session(tick_start, tick_end, rank);
	}
}

static ECMBOOL
is_solo_session(session_t *session, ecm_uint32 tick)
{
	struct list_head	*lp;
	session_t	*session_list;

	for (lp = session->list.next; lp != &sessions; lp = lp->next) {
		session_list = list_entry(lp, session_t, list);
		if (session_list->tick_start > tick)
			break;
		if (session_list->tick_start <= tick && session_list->tick_end >= tick) {
			if (session_list->rank == session->rank)
				return ECM_TRUE;
		}
	}

	for (lp = session->list.prev; lp != &sessions; lp = lp->prev) {
		session_list = list_entry(lp, session_t, list);
		if (session_list->tick_end < tick)
			break;
		if (session_list->tick_start <= tick && session_list->tick_end >= tick) {
			if (session_list->rank == session->rank)
				return ECM_TRUE;
		}
	}

	return ECM_FALSE;
}

static void
check_n_sessions(ecm_uint32 tick, ecm_uint32 *pn_sessions, ecm_uint32 *pn_solo_sessions)
{
	session_t	*session;
	struct list_head	*lp;
	ecm_uint32	n_sessions = 0, n_solo_sessions = 0;

	list_for_each (lp, &sessions) {
		session = list_entry(lp, session_t, list);
		if (session->tick_start <= tick && session->tick_end >= tick) {
			n_sessions++;
			if (is_solo_session(session, tick))
				n_solo_sessions++;
		}
	}
	*pn_sessions = n_sessions;
	*pn_solo_sessions = n_solo_sessions;
}

static void
doit(void)
{
	ecm_uint32	tick;

	for (tick = start + 60; tick < end; tick += 60) {
		ecm_uint32	n_sessions, n_solo_sessions;

		check_n_sessions(tick, &n_sessions, &n_solo_sessions);
		printf("%d %d\n", n_sessions, n_solo_sessions);
	}
}

static session_t *
find_next_session(session_t *session)
{
	session_t	*session_next;
	struct list_head	*lp;

	for (lp = session->list.next; lp != &sessions; lp = lp->next) {
		session_next = list_entry(lp, session_t, list);
		if (session_next->rank == session->rank)
			return session_next;
	}

	return NULL;
}

static void
check_interval(void)
{
	session_t	*session, *session_next;
	struct list_head	*lp;
	ecm_uint32	*data;
	ecm_uint32	i, j;
	ecm_uint32	count = 0;

	data = (ecm_uint32 *)ecm_calloc(100, sizeof(ecm_uint32));

	list_for_each (lp, &sessions) {
		session = list_entry(lp, session_t, list);
		session_next = find_next_session(session);
		if (session_next && session_next->tick_start > session->tick_start) {
			ecm_uint32	interval = session_next->tick_start - session->tick_start;
			if (interval >= 1800 && interval < 3600 && session->rank <= 300) {
				data[(session->rank - 1) / 30 * 10 + (interval - 1800)/ 180]++;
				count++;
			}
		}
	}

	for (i = 0; i < 10; i++) {
		for (j = 0; j < 10; j++) {
			printf("%u %u %lf\n", i + 1, j + 1, ((ecm_double)data[i * 10 + j]) / count);
		}
	}
}

int
main(int argc, char *argv[])
{
	ECM_initialize();

	parse_args(argc, argv);

	ecm_set_output_file(ecm_stderr);
	ecm_set_verbose_mode(ECM_TRUE);

	load_session();

	///check_interval();///TEST

	doit();

	return 0;
}
